{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1 The Processes and Threads\n",
    "\n",
    "\n",
    "## 1.1  Process \n",
    "\n",
    "**Process(task): is a program in execution**\n",
    "\n",
    "Each process is an `independent entity to which system resources` such as CPU time, memory, etc. are allocated and each process is executed in `a separate address space`. \n",
    "\n",
    "> 一个进程是一个正在运行的程序, 是资源（CPU、内存等）分配的基本单位\n",
    "\n",
    "If we want to access another process' resources, `inter-process communications` have to be used such as pipes, files, sockets etc.\n",
    "\n",
    "Process provides each program with **two key abstractions**:\n",
    "\n",
    "* Logical control flow\n",
    "  * Each process seems to have exclusive use of the CPU\n",
    "  \n",
    "* Private virtual address space\n",
    "  * Each process seems to have exclusive use of main memory\n",
    "\n",
    "When a process is created, the operating system allocates a data structure that contains information about the process, called a process control block or PCB. \n",
    "\n",
    "Among other things, the PCB keeps track of the **process state(进程状态)**, which is one of:\n",
    "\n",
    "* **Running(运行)**, if the process is currently running on a core.\n",
    "\n",
    "* **Ready(就绪)**, if the process could be running, but isn’t, usually because there are more runnable processes than cores.\n",
    "\n",
    "* **Blocked(阻塞)**, if the process cannot run because it is waiting for a future  event like network communication or a disk read.\n",
    "\n",
    "* **Done(终止)**, if the process has completed, but has exit status information that has not been read yet.\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.2 Thread\n",
    "\n",
    "**A thread is a `separate` flow of execution that can run `concurrently(并发）` to solve a problem in the process.** \n",
    "\n",
    "This means that your program will have two things happening at once.\n",
    "\n",
    "For example\n",
    "\n",
    "* a Web browser uses one thread to load an image from the Internet while using another thread to format and display text.\n",
    "\n",
    "More exactly it is `Thread of Execution` which is the **smallest** unit of processing.\n",
    "\n",
    ">一个线程是进程中可以并发运行的独立执行流,是CPU调度和分派的基本单位(程序执行时的最小单位)\n",
    "\n",
    "* It is scheduled by an OS.\n",
    "\n",
    "* It is contained in a process. so, multiple threads can exist within the same process.\n",
    "\n",
    "* It **shares** the resources with the process: The memory, code (instructions), and global variable\n",
    "\n",
    "* Each thread still has its **own** stack of activation records and its own copy of CPU registers, including the stack pointer and the program counter, which together describe the state of the thread's execution.\n",
    "\n",
    "* On a single processor, each thread has its turn by multiplexing(多路复用) based on time. On a multiple processor, each thread is running at the same time with each processor/core running a particular thread.\n",
    "\n",
    "\n",
    "**Multithreading provides several advantages.**\n",
    "\n",
    "* Threads are useful in inter-process communication. They also improve responsiveness. \n",
    "* It is not necessary to allocate resources to each thread separately so, using threads are economical.\n",
    "* If one thread fails, that will not affect the whole process.\n",
    "* Threads are light-weight and consume a minimum amount of resources compared with a process.\n",
    " "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.3 Processes vs Threads\n",
    "\n",
    "Processes and threads are related to each other but are fundamentally different.\n",
    "\n",
    "1. Processes are independent while thread is within a process.\n",
    "\n",
    "2. Processes have separate address spaces while threads share their address spaces.\n",
    "\n",
    "3. Processes communicate each other through inter-process communication.\n",
    "\n",
    "4. Processes carry considerable state (e.g., ready, running, waiting, or stopped) information, whereas multiple threads within a process share state as well as memory and other resources.\n",
    "\n",
    "5. Context switching between threads in the same process is typically faster than context switching between processes.\n",
    "\n",
    "6. Multithreading has some advantages over multiple processes. Threads require less overhead to manage than processes, and intraprocess thread communication is less expensive than interprocess communication.\n",
    "\n",
    "7. Multiple process concurrent programs do have one advantage: Each process can execute on a different machine (distribute program). \n",
    "\n",
    "**The `key` difference between processes and threads** is that \n",
    "\n",
    "* `multiple` threads `share(共享)` parts of their state. \n",
    "\n",
    "* a thread is a particular `execution path(运行路径)` of a process. \n",
    ">\n",
    ">多个线程共享进程资源，每个线程有自己的堆栈和局部变量共享状态\n",
    ">\n",
    ">线程包含在进程之中,是进程的一个运行路径\n",
    "\n",
    "![thread](./img/linux/ThreadDiagram.jpg)\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.4 MultiProcessing vs Multithreading \n",
    " \n",
    " Multiprocessing and multithreading can affect system performance. \n",
    " \n",
    "**What are the Similarities** \n",
    "\n",
    "Both methods can\n",
    "\n",
    "* increase CPU utilization.\n",
    "* increase computing speed.\n",
    " \n",
    "**What is the Difference**\n",
    "\n",
    "The key difference between multiprocessing and multithreading is that, \n",
    " \n",
    " * Multiprocessing: multiple processes are running concurrently using two or more **processors** \n",
    " \n",
    " * Multithreading, multiple threads `in a process` are running concurrently.\n",
    " \n",
    " <table>\n",
    "<tbody>\n",
    "<tr>\n",
    "<td style=\"background-color: #324b7a;\" colspan=\"2\">\n",
    "<h3 style=\"text-align: center;\"><span style=\"color: #ffffff;\">Multiprocessing vs Multithreading</span></h3>\n",
    "</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td style=\"background-color: #e3ebfa; padding-left: 30px;\">Multiprocessing is to execute multiple processes using two or more processes concurrently to improve the system performance.</td>\n",
    "<td style=\"background-color: #f7f9fc; padding-left: 30px;\">Multithreading is to execute multiple threads in a process concurrently to improve system performance.</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td style=\"background-color: #5c739e; text-align: center;\" colspan=\"2\"><b> <span style=\"color: #ffffff;\">Execution</span></b></td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td style=\"background-color: #e3ebfa; padding-left: 30px;\">In Multiprocessing, multiple processes are running concurrently.</td>\n",
    "<td style=\"background-color: #f7f9fc; padding-left: 30px;\">In Multithreading, multiple threads in a single process are running concurrently.</td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td style=\"background-color: #5c739e; text-align: center;\" colspan=\"2\"><span style=\"color: #ffffff;\"><b>Resource Requirements</b></span></td>\n",
    "</tr>\n",
    "<tr>\n",
    "<td style=\"background-color: #e3ebfa; padding-left: 30px;\">Multiprocessing requires more resources.</td>\n",
    "<td style=\"background-color: #f7f9fc; padding-left: 30px;\">Multithreading does not require many resources; therefore, it is more economical.</td>\n",
    "</tr>\n",
    "</tbody>\n",
    "</table>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.5 Concurrency vs Parallelism \n",
    "\n",
    "**Concurrency(并发)**  means multiple tasks which start, run, and complete `in overlapping time periods`, in no specific order\n",
    "\n",
    "**Parallelism(并行)** is the task of running multiple computations **simultaneously**.\n",
    "\n",
    "> 并发：在一个时间段内，有多个任务都处于已启动、运行和运行完成之间.宏观上看起来多个任务都在同一时刻运行，但多个任务指令在交织着运行。\n",
    ">\n",
    "> 并行：在同一时刻，有多个任务同时在执行\n",
    ">\n",
    "> 并发是在同一时段发生,并行是在同一时刻发生\n",
    "\n",
    "\n",
    "* Concurrent = Two queues and one coffee machine.\n",
    "\n",
    "* Parallel = Two queues and two coffee machines.\n",
    "\n",
    "![](./img/linux/con_and_par.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.6  Parallelism and Parallel Computing\n",
    "\n",
    "**Parallelism**\n",
    "\n",
    "The term parallelism means that an application `splits` its tasks up into smaller **subtasks** which can be processed in parallel, for instance on multiple CPUs at the exact same time.\n",
    "\n",
    "**Parallel Computing**\n",
    "\n",
    "In the simplest sense, parallel computing is the simultaneous use of multiple compute resources to solve a computational problem:\n",
    "\n",
    "* A problem is broken into discrete parts that can be solved concurrently\n",
    "\n",
    "* Each part is further broken down to a series of instructions\n",
    "\n",
    "* Instructions from each part execute simultaneously on different processors\n",
    "\n",
    "* An overall control/coordination mechanism is employed\n",
    "\n",
    "![Parallelism](./img/linux/parallelProblem.gif)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1.7 Parallelizing a problem\n",
    "\n",
    "**divide and conquer(分治）**\n",
    "\n",
    "When you face a complex issue, the first thing to be done is to decompose the problem in order to identify **parts** of it that may be handled **independently.**\n",
    "\n",
    "In general, the parallelizable parts in a solution are in pieces that can be divided and distributed for them to be processed by different workers. \n",
    "\n",
    "The technique of `dividing and conquering` involves splitting the domain recursively until an indivisible unit of the complete issue is found and solved. \n",
    "\n",
    "The sort algorithms, such as **merge** sort and **quick** sort（合并、快速排序）, can be resolved by using this approach"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2 GUI and Threading\n",
    "\n",
    "* **blocking(阻塞) GUI** :the single GUI thread with **infinite** loop\n",
    "\n",
    "* **unblocking GUI**: the GUI thread and **I/O** thread\n",
    "\n",
    ">**Blocking** The action or data that the call is requesting **not be available** at the time the call is made, so the call will `wait` for the other end to respond in some fashion before returning to the caller.\n",
    ">it will also effectively `suspend your application` until it returns.\n",
    "\n",
    "## 2.1 PyQt5 "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting ./code/python/pyqt5-gui.py\n"
     ]
    }
   ],
   "source": [
    "%%file ./code/python/pyqt5-gui.py\n",
    "import sys\n",
    "from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication\n",
    "\n",
    "class Example(QMainWindow):\n",
    "    \n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.initUI()\n",
    "        \n",
    "        \n",
    "    def initUI(self):      \n",
    "\n",
    "        btn1 = QPushButton(\"Button 1\", self)\n",
    "        btn1.move(30, 50)\n",
    "\n",
    "        btn2 = QPushButton(\"Button 2\", self)\n",
    "        btn2.move(150, 50)\n",
    "      \n",
    "        btn1.clicked.connect(self.buttonClicked)            \n",
    "        btn2.clicked.connect(self.buttonClicked)\n",
    "        \n",
    "        self.statusBar()\n",
    "        \n",
    "        self.setGeometry(300, 300, 290, 150)\n",
    "        self.setWindowTitle('The Demo GUI')\n",
    "        self.show()\n",
    "        \n",
    "    def buttonClicked(self):\n",
    "        sender = self.sender()\n",
    "        self.statusBar().showMessage(sender.text() + ' was pressed')\n",
    "        \n",
    "        \n",
    "if __name__ == '__main__':\n",
    "    app = QApplication(sys.argv)\n",
    "    ex = Example()\n",
    "    sys.exit(app.exec_())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run ./code/python/pyqt5-gui.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.2 Qt\n",
    "\n",
    "[Qt](www.qt.io) is a free and open-source widget toolkit for creating **graphical user interfaces** as well as cross-platform applications that run on various software and hardware platforms such as Linux, Windows, macOS, Android or embedded systems with little or no change in the underlying codebase while still being a native application with native capabilities and speed.\n",
    "\n",
    "One framework. One codebase. Any platform.\n",
    "\n",
    "Everything you need for your entire software development life cycle. Qt is the fastest and smartest way to produce industry-leading software that users love.\n",
    "\n",
    "[PyQt](https://riverbankcomputing.com/software/pyqt/intro)\n",
    "\n",
    "PyQt is a set of Python v2 and v3 bindings for The Qt Company's Qt application framework and runs on all platforms supported by Qt including Windows, OS X, Linux, iOS and Android. PyQt5 supports Qt v5. PyQt4 supports Qt v4 and will build against Qt v5. The bindings are implemented as a set of Python modules and contain over 1,000 classes.\n",
    "\n",
    "\n",
    "**install PyQt5 for Windows**\n",
    "\n",
    "```\n",
    ">python -m pip install PyQt5 -i  https://pypi.tuna.tsinghua.edu.cn/simple\n",
    "\n",
    ">python -m pip install PyQt5-tools -i https://pypi.tuna.tsinghua.edu.cn/simple\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3 The  PyQt Application"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting ./code/python/thesimplestqt.py\n"
     ]
    }
   ],
   "source": [
    "%%file ./code/python/thesimplestqt.py\n",
    "import sys\n",
    "from PyQt5.QtWidgets import QApplication, QWidget,QMainWindow\n",
    "\n",
    "class Example(QMainWindow): \n",
    "    \n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.setGeometry(300, 300, 290, 150)\n",
    "        self.setWindowTitle('Simple')\n",
    "        self.show()\n",
    "        \n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    app = QApplication(sys.argv) # 1 Every PyQt5 applicationmust create an application object.\n",
    "    ex=Example()                 # 2 create GUI in memory and later show on the screen.\n",
    "    sys.exit(app.exec_())  # 3 The sys.exit() method ensures a clean exit. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run ./code/python/thesimplestqt.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**1 app = QApplication(sys.argv)**\n",
    "\n",
    "* Every PyQt5 application` must create an application object`. \n",
    "\n",
    "* The `sys.argv` parameter is a list of arguments from a command line\n",
    "\n",
    "**2 show()**\n",
    "\n",
    "* The `show()` method displays the widget on the screen. A widget is first created in memory and later shown on the screen.\n",
    "\n",
    "**3 sys.exit(app.exec_())** \n",
    "\n",
    "* we enter the mainloop of the application. The event handling starts from this point. The mainloop receives events from the window system and dispatches them to the application widgets.\n",
    "\n",
    "* The mainloop ends if we call the `exit()` method or the main widget is destroyed. The `sys.exit()` method ensures a clean exit. The environment will be informed how the application ended"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.4 Widgets \n",
    "\n",
    "Widgets are basic building blocks of an application.\n",
    "\n",
    "PyQt5 has a wide range of various widgets, including `buttons, check boxes, sliders, or list boxes`\n",
    "\n",
    "```python\n",
    "from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication\n",
    "\n",
    " btn2 = QPushButton(\"Button 2\", self)\n",
    "```\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.5 Layout management in PyQt5\n",
    "\n",
    "`Layout management` is the way how we place the widgets on the application window. \n",
    "\n",
    "We can place our widgets using `absolute positioning` or with `layout classes`.\n",
    "\n",
    "Managing the layout with layout managers is the preferred way of organizing our widgets.\n",
    "\n",
    "**Absolute positioning**\n",
    "\n",
    "The programmer specifies the position and the size of each widget in pixels. \n",
    "\n",
    "```python\n",
    " btn2.move(150, 50)\n",
    "```\n",
    "\n",
    "**Relative Layout**\n",
    "\n",
    "* QHBoxLayout QVBoxLayout \n",
    "\n",
    "* QGridLayout"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.6 Events,Signals and slots\n",
    "\n",
    "#### 1 Events\n",
    "\n",
    "**GUI applications are event-driven.**\n",
    "\n",
    "Events are generated mainly by the user of an application. But they can be generated by other means as well; e.g. an Internet connection, a window manager, or a timer. \n",
    "\n",
    "When we call the application's `exec_()` method, the application enters the main loop. The main loop fetches events and sends them to the objects.\n",
    "\n",
    "In the event model, there are three participants:\n",
    "\n",
    "* event source\n",
    "* event object\n",
    "* event target\n",
    "\n",
    "The `event source` is the object whose `state changes`. It generates events. \n",
    "\n",
    "The `event object (event)` encapsulates the state changes in the event source. \n",
    "\n",
    "The `event target` is the object that wants to be notified. \n",
    "\n",
    "\n",
    "#### 2  signal and slot\n",
    "\n",
    "PyQt5 has a unique `signal and slot` mechanism to deal with events.\n",
    "\n",
    "`Signals and slots` are used for communication between objects. \n",
    "\n",
    "* A `signal` is emitted when a particular event occurs. \n",
    "\n",
    "* A `slot` can be any Python callable. A slot is called when its connected signal is emitted.\n",
    "\n",
    "```python\n",
    "btn2.clicked.connect(self.button2Clicked)\n",
    "```\n",
    "\n",
    "```python\n",
    "  def button2Clicked(self):\n",
    "        while True:\n",
    "            self.value=get_data()\n",
    "            self.statusBar().showMessage(str(self.value))   \n",
    "            time.sleep(2)\n",
    "```            \n",
    "Here we connect a `clicked` signal of the button to the slot of the `button2Clicked()` methof."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.2  Unresponsive Blocking GUI \n",
    "\n",
    "* the single GUI thread with infinite loop\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      " cpu percent is  0.0\n"
     ]
    }
   ],
   "source": [
    "import psutil\n",
    "\n",
    "def io_cpu_percent():\n",
    "    return psutil.cpu_percent()\n",
    "\n",
    "value=io_cpu_percent()\n",
    "print(\" cpu percent is \",value)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2  Blocking GUI App"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Overwriting ./code/python/pyqt5-gui-unresponsive.py\n"
     ]
    }
   ],
   "source": [
    "%%file ./code/python/pyqt5-gui-unresponsive.py\n",
    "import sys\n",
    "from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication\n",
    "\n",
    "import time\n",
    "import psutil\n",
    "\n",
    "def get_data():\n",
    "    return psutil.cpu_percent()\n",
    "\n",
    "class Example(QMainWindow):\n",
    "    \n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.initUI()\n",
    "        \n",
    "    def initUI(self):      \n",
    "        btn1 = QPushButton(\"Button 1\", self)\n",
    "        btn1.move(30, 50)\n",
    "\n",
    "        btn2 = QPushButton(\"Start Read CPU\", self)\n",
    "        btn2.move(150, 50)\n",
    "      \n",
    "        btn1.clicked.connect(self.button1Clicked)            \n",
    "        btn2.clicked.connect(self.button2Clicked)\n",
    "        \n",
    "        self.statusBar()\n",
    "        \n",
    "        self.setGeometry(300, 300, 290, 150)\n",
    "        self.setWindowTitle('Read CPU,non-threading')\n",
    "        self.show()\n",
    "        \n",
    "        \n",
    "    def button1Clicked(self):\n",
    "        sender = self.sender()\n",
    "        self.statusBar().showMessage(sender.text() + ' was pressed')\n",
    "    \n",
    "    def button2Clicked(self):\n",
    "        # infinite loop\n",
    "        while True:\n",
    "            self.value=get_data()\n",
    "            self.statusBar().showMessage(str(self.value))   \n",
    "            time.sleep(2)\n",
    "        \n",
    "if __name__ == '__main__':\n",
    "    app = QApplication(sys.argv)\n",
    "    ex = Example()\n",
    "    sys.exit(app.exec_())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run ./code/python/pyqt5-gui-unresponsive.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.3 Threads\n",
    "\n",
    "**Threads** describe processes that can run **concurrently** to solve a problem.\n",
    "\n",
    "A thread is a `separate` flow of execution. This means that your program will have two things happening at once.\n",
    "\n",
    "**Python threading module**\n",
    "\n",
    "Python includes sophisticated tools for managing concurrent operations using processes and threads. Even many relatively simple programs can be made to run faster by applying techniques for running parts of the job concurrently using these modules.\n",
    "\n",
    "The **threading** module includes a high-level, object-oriented API for working with concurrency from Python. \n",
    "\n",
    "Thread objects run **concurrently** within the same process and share memory. \n",
    "\n",
    "### 3.1 Thread Objects\n",
    "\n",
    "The simplest way to use a Thread is to instantiate it with a **target** function and call **start()** to let it begin working.\n",
    "\n",
    "* The following example's output is five lines with \"Worker\" on each."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import threading\n",
    "import time\n",
    "def worker():\n",
    "    \"\"\"thread worker function\"\"\"\n",
    "    time.sleep(0.5)\n",
    "    print('Worker')\n",
    "\n",
    "print(\"Main Begin\")\n",
    "threads = []\n",
    "for i in range(5):\n",
    "    t = threading.Thread(target=worker)\n",
    "    threads.append(t)\n",
    "    t.start()\n",
    "print(\"Main End\")    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 arguments\n",
    "\n",
    "It is useful to be able to spawn a thread and pass **arguments** that tell it which work to do.\n",
    "\n",
    "* `Any type of object` can be passed as `argument` to the thread. \n",
    "\n",
    "The next example passes a number, which the thread then prints.\n",
    "\n",
    "* The integer argument is now included in the message printed by each thread.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import threading\n",
    "\n",
    "def worker(num):\n",
    "    \"\"\"thread worker function\"\"\"\n",
    "    print('Worker: %s' % num)\n",
    "\n",
    "threads = []\n",
    "for i in range(5):\n",
    "    t = threading.Thread(target=worker, args=(i,))\n",
    "    threads.append(t)\n",
    "    t.start()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2.4 Unblcoking GUI  \n",
    "\n",
    "We’ll look at the way to realize **unblocking GUI** using **Multithreading**.\n",
    "\n",
    "* Threading IO"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "code_folding": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Writing ./code/python/pyqt5-gui-responsive.py\n"
     ]
    }
   ],
   "source": [
    "%%file ./code/python/pyqt5-gui-responsive.py\n",
    "import sys\n",
    "from PyQt5.QtWidgets import QMainWindow, QPushButton, QApplication\n",
    "\n",
    "import time\n",
    "import psutil\n",
    "import threading\n",
    "\n",
    "def get_data():\n",
    "    return psutil.cpu_percent()\n",
    "\n",
    "class Example(QMainWindow):\n",
    "    \n",
    "    def __init__(self):\n",
    "        super().__init__()\n",
    "        self.initUI()\n",
    "        \n",
    "    def initUI(self):      \n",
    "\n",
    "        btn1 = QPushButton(\"Button 1\", self)\n",
    "        btn1.move(30, 50)\n",
    "\n",
    "        self.btn2 = QPushButton(\"Start CPU\", self)\n",
    "        self.btn2.move(150, 50)\n",
    "      \n",
    "        btn1.clicked.connect(self.button1Clicked)            \n",
    "        self.btn2.clicked.connect(self.button2Clicked)\n",
    "        \n",
    "        self.statusBar()\n",
    "        \n",
    "        self.setGeometry(300, 300, 290, 150)\n",
    "        self.setWindowTitle('Threading IO')\n",
    "        self.show()\n",
    "        \n",
    "        \n",
    "    def button1Clicked(self):\n",
    "        sender = self.sender()\n",
    "        self.statusBar().showMessage(sender.text() + ' was pressed')\n",
    "\n",
    "    def io_worker(self):\n",
    "        \"\"\"thread's worker function\"\"\"\n",
    "        while True:\n",
    "            self.value=get_data()\n",
    "            self.statusBar().showMessage(str(self.value))  \n",
    "            time.sleep(2)\n",
    "     \n",
    "    def button2Clicked(self):\n",
    "        # Threading IO\n",
    "        self.t = threading.Thread(target=self.io_worker)\n",
    "        self.t.start()\n",
    "        \n",
    "if __name__ == '__main__':\n",
    "    app = QApplication(sys.argv)\n",
    "    ex = Example()\n",
    "    sys.exit(app.exec_())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run ./code/python/pyqt5-gui-responsive.py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![threading](./img/linux/gui-background-threading.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Reference\n",
    "\n",
    "**Qt**\n",
    "\n",
    "* [Qt](https://www.qt.io)\n",
    "\n",
    "* [PyQt](https://riverbankcomputing.com/software/pyqt/intro)\n",
    "\n",
    "* [PyQt5 tutorial](http://zetcode.com/gui/pyqt5/)\n",
    "\n",
    "**Threading**\n",
    "\n",
    "* The Python Standard Library [threading — Thread-based parallelism](https://docs.python.org/3/library/threading.html)\n",
    "\n",
    "* Doug Hellmann.[threading — Manage Concurrent Operations Within a Process](https://pymotw.com/3/threading/index.html)\n",
    "  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.7"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "211px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
